package org.ainlolcat.ainscience.statistics.handlers.fitting;

import org.ainlolcat.ainscience.UI.renderer.LineDataRenderer;
import org.ainlolcat.ainscience.UI.renderer.LineRendererSource;
import org.ainlolcat.ainscience.column.Column;
import org.ainlolcat.ainscience.entity.Entity;
import org.ainlolcat.ainscience.statistics.StatisticHandler;
import org.ainlolcat.ainscience.statistics.StatisticStorage;
import org.ainlolcat.ainscience.utils.ArraysUtil;
import org.ainlolcat.ainscience.utils.XMLUtils;
import org.apache.log4j.Logger;
import org.jdom.Element;

import javax.swing.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Hashtable;
import java.util.List;

/**
 * @author ainlolcat
 * Date: 09.03.12
 */
public class MultiplePeakFittingStatisticHandler implements StatisticHandler, LineRendererSource {
    private static Logger log = Logger.getLogger(MultiplePeakFittingStatisticHandler.class);
    Hashtable<String, double[][]> data = new Hashtable<String, double[][]>();
    int baseline = -1;
    boolean gaussPrediction = false;

    public JPanel getRenderer() {
        return new LineDataRenderer(this);
    }

    public Hashtable<String, String> getStatistic(Entity entity, Integer columnID) {
        return getStatistic(entity, columnID, null);
    }

    public Hashtable<String, String> getStatistic(Entity entity, Integer columnID, Element params) {
        Hashtable<String,String> stats = new Hashtable<String, String>();
        Column cy = entity.getColumnByOrder(columnID);
        if (cy.isNumeric()){
            Column cx = entity.getXColumn(cy.getAxis());
            if (cx.isNumeric()){
                double[] x = cx.getDoubleRepresentation();
                double[] y = cy.getDoubleRepresentation();
                baseline = XMLUtils.getSafeInteger4Children(params, "baseline", -1);
                gaussPrediction = XMLUtils.getSafeBoolean4Children(params, "gaussPreApp", true);
                if (params == null || params.getChildren("range").isEmpty()){
                    throw new IllegalArgumentException("Parameters required");
                }else {
                    for (Element integral:(List<Element>)params.getChildren("range")){
                        //try retrieve settings from params
                        double start = XMLUtils.getSafeDouble4Attribute(integral, "start", x[0]);
                        double end = XMLUtils.getSafeDouble4Attribute(integral, "end", x[x.length-1]);
                        String name = XMLUtils.getSafeString4Attribute(integral, "name", "MPeak " + start + " " + end);
                        double[][] cutted = ArraysUtil.cut(x, y, start, end);

                        List<Element> ePeaks = (List<Element>)integral.getChildren("peak");
                        List<Peak> peaks = new ArrayList<Peak>();

                        for (int i=0;i < ePeaks.size() ; i++){
                            Element peak = ePeaks.get(i);
                            Peak temp = new Peak();
                            temp.A = XMLUtils.getSafeDouble4Attribute(peak, "A", 1.0);
                            temp.x0 = XMLUtils.getSafeDouble4Attribute(peak, "center", 1.0 * (start + end) / 2);
                            temp.w = XMLUtils.getSafeDouble4Attribute(peak, "width", 1.0 * (end - start)/2);
                            temp.fixed = XMLUtils.getSafeBoolean4Attribute(peak, "fixed", false);
                            peaks.add(temp);
                        }

                        peaks = new MultipleGaussPeakFitting(this).getParamsFor(cutted[0], cutted[1], peaks, name);
                        populateStats(entity, name, stats, peaks);
                    }
                }
            }
        }
        return stats;
    }

    private void populateStats(Entity entity, String name, Hashtable<String,String> stats, List<Peak> peaks ){
        StatisticStorage.getInstance().registerHandler(entity, name, this);
        if (peaks == null) return;
        for (int i = 0;i<peaks.size();i++){
            double center = peaks.get(i).x0;
            StatisticStorage.getInstance().registerHandler(entity, name + " at " + center + " A",this);
            StatisticStorage.getInstance().registerHandler(entity, name + " at " + center + " width",this);
            StatisticStorage.getInstance().registerHandler(entity, name + " at " + center + " center", this);
            stats.put(name + " at " + center + " A", Double.toString(peaks.get(i).A));
            stats.put(name + " at " + center + " width", Double.toString(peaks.get(i).w));
            stats.put(name + " at " + center + " center", Double.toString(peaks.get(i).x0));
        }
        StatisticStorage.getInstance().registerHandler(entity, name + " eps",this);
        double [][] temp = data.get(name);
        stats.put(name + " eps", Double.toString(ArraysUtil.getNormalizedDifference(temp[0], temp[1], temp[2])[1]));
    }

    public Collection<String> getNames() {
        return data.keySet();
    }

    public double[][] getData(String name) {
        return data.get(name);
    }

}
